package com.color.admin.common.logger.aspecct;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.JSONPatch;
import com.color.admin.auth.entity.LoginDto;
import com.color.admin.common.core.constant.Constant;
import com.color.admin.common.core.result.ResultCode;
import com.color.admin.common.core.result.ResultData;
import com.color.admin.common.core.utils.web.ServletUtils;
import com.color.admin.common.core.utils.web.StringUtils;
import com.color.admin.common.core.utils.web.ToolUtils;
import com.color.admin.common.logger.annotation.Log;
import com.color.admin.common.logger.service.LogService;
import com.color.admin.log.entity.SysLog;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.*;

/**
 * @author HaiQiu
 * @date 2022/1/24
 */
@Aspect
@Component
@Order(0)
public class LogAspect {

    ThreadLocal<Long> currentTime = new ThreadLocal<>();

    @Autowired
    private LogService logService;

    @Pointcut(value = "@annotation(com.color.admin.common.logger.annotation.Log)")
    public void logPointcut() {
        // 该方法无方法体,主要为了让同类中其他方法使用此切入点
    }


    @AfterReturning(pointcut = "logPointcut()",returning = "jsonResult")
    public void logAround(JoinPoint joinPoint,Object jsonResult){
        ResultData resultData = (ResultData) jsonResult;
        SysLog sysLog = handlerParams(joinPoint);
        if (resultData.getCode()!= ResultCode.OK.getCode()){
            sysLog.setLevel("warn");
        }else {
            sysLog.setLevel("info");
        }
        sysLog.setCode(String.valueOf(resultData.getCode()));
        sysLog.setResponse(JSONObject.toJSONString(jsonResult));
        logService.save(sysLog);
    }

    @AfterThrowing(pointcut = "logPointcut()", throwing = "e")
    public void logAfterThrowing(JoinPoint joinPoint, Throwable e){
        SysLog sysLog = handlerParams(joinPoint);
        ResultData resultData = ResultData.fail(e.getMessage());
        sysLog.setLevel("error");
        sysLog.setResponse(JSONObject.toJSONString(resultData));
        sysLog.setCode(String.valueOf(resultData.getCode()));
        logService.save(sysLog);
    }


    private SysLog handlerParams(JoinPoint joinPoint) {
        currentTime.set(System.currentTimeMillis());
        HttpServletRequest request = ServletUtils.getRequest();

        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        Log log = method.getAnnotation(Log.class);

        SysLog sysLog = new SysLog();
        sysLog.setRequest(getParams(method, joinPoint.getArgs()));
        sysLog.setClient(ToolUtils.getBrowser());
        sysLog.setOs(ToolUtils.osName());
        sysLog.setIp(ToolUtils.getIp());
        sysLog.setMethod(request.getMethod());
        sysLog.setUrl(request.getServletPath());
        sysLog.setOperaId(ServletUtils.getUserId());
        sysLog.setUser(ServletUtils.getUsername());
        sysLog.setName(log.value());
        sysLog.setCreateTime(new Date());
        if (sysLog.getIp().equals(Constant.LOCALHOST)){
            sysLog.setLocation("本机内网");
        }else {
            sysLog.setLocation(ToolUtils.getLocation());
        }

        getLoginUser(log, sysLog);

        sysLog.setConsume(System.currentTimeMillis() - currentTime.get() + "ms");
        currentTime.remove();
        return sysLog;
    }

    private void getLoginUser(Log log, SysLog sysLog) {
        String login1 = "登录接口";
        String login2 = "用户登录";
        if (log.value().contains(login1) || log.value().contains(login2)){
            JSONArray objects = JSONObject.parseArray(sysLog.getRequest());
            LoginDto loginDto = JSONObject.parseObject(objects.getJSONObject(0).toJSONString(), LoginDto.class);
            loginDto.setPassword("**********");
            sysLog.setUser(loginDto.getUsername());
            JSONArray loginDtos  = new JSONArray();
            loginDtos.add(loginDto);
            sysLog.setRequest(JSONObject.toJSONString(loginDtos));
        }
    }


    public String getParams(Method method, Object[] args) {
        List<Object> argList = new ArrayList<>();
        Parameter[] parameters = method.getParameters();
        for (int i = 0; i < parameters.length; i++) {
            //将RequestBody注解修饰的参数作为请求参数
            RequestBody requestBody = parameters[i].getAnnotation(RequestBody.class);
            if (requestBody != null) {
                argList.add(args[i]);
            }
            //将RequestParam注解修饰的参数作为请求参数
            RequestParam requestParam = parameters[i].getAnnotation(RequestParam.class);
            if (requestParam != null) {
                Map<String, Object> map = new HashMap<>();
                String key = parameters[i].getName();
                if (!StringUtils.isBlank(requestParam.value())) {
                    key = requestParam.value();
                }
                map.put(key, args[i]);
                argList.add(map);
            }
        }
        if (CollectionUtils.isEmpty(argList) || argList.isEmpty()) {
            return "";
        }
        return JSONObject.toJSONString(argList);
    }
}
